import { getBusinessObject, is } from 'bpmn-js/lib/util/ModelUtil'
import { createModdleElement, getExtensionElementsList, addExtensionElements, removeExtensionElements } from './bpmnPropertyUtils/extensionElements'
import { useSettingStore } from '@/store/bpmnProcess/settingStore'
import { useModelerStore } from '@/store/bpmnProcess/modelerStore'

export function isCalledElementSupported(element) {
  return is(element, 'bpmn:CallActivity')
}

export function getCalledElementTypeValue(element) {
  return getCalledElementType(element)
}
export function setCalledElementTypeValue(element, value) {
  const prefix = useSettingStore().editor.processEngine
  const modeling = useModelerStore().getModeling
  const properties = {
    ...setDefaultProps()
  }
  if (value === 'bpmn') {
    properties['calledElement'] = ''
  } else if (value === 'cmmn') {
    properties[`${prefix}:caseRef`] = ''
  }
  modeling.updateProperties(element, properties)
}

export function getCalledElementValue(element) {
  console.log(getBusinessObject(element).get('calledElement'), '获取元素信息')
  return getBusinessObject(element).get('calledElement')
}
export function setCalledElementValue(element, value) {
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    calledElement: value || ''
  })
}

export function getCalledElementBindingTypeValue(element) {
  const prefix = useSettingStore().editor.processEngine
  return getBusinessObject(element).get(`${prefix}:calledElementBinding`) || 'latest'
}
export function setCalledElementBindingTypeValue(element, value) {
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    calledElementBinding: value === 'latest' ? undefined : value,
    calledElementVersion: undefined,
    calledElementVersionTag: undefined
  })
}

export function getCalledElementVersionValue(element) {
  const prefix = useSettingStore().editor.processEngine
  return getBusinessObject(element).get(`${prefix}:calledElementVersion`)
}
export function setCalledElementVersionValue(element, value) {
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    calledElementVersion: value
  })
}

export function getCalledElementVersionTagValue(element) {
  const prefix = useSettingStore().editor.processEngine
  return getBusinessObject(element).get(`${prefix}:calledElementVersionTag`)
}
export function setCalledElementVersionTagValue(element, value) {
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    calledElementVersionTag: value
  })
}

export function getCalledElementTenantIdValue(element) {
  const prefix = useSettingStore().editor.processEngine
  return getBusinessObject(element).get(`${prefix}:calledElementTenantId`)
}
export function setCalledElementTenantIdValue(element, value) {
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    calledElementTenantId: value
  })
}

export function getCaseRefValue(element) {
  const prefix = useSettingStore().editor.processEngine
  return getBusinessObject(element).get(`${prefix}:caseRef`)
}
export function setCaseRefValue(element, value) {
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    caseRef: value || ''
  })
}

export function getCaseRefBindingTypeValue(element) {
  const prefix = useSettingStore().editor.processEngine
  return getBusinessObject(element).get(`${prefix}:caseBinding`) || 'latest'
}
export function setCaseRefBindingTypeValue(element, value) {
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    caseBinding: value === 'latest' ? undefined : value,
    caseVersion: undefined
  })
}

export function getCaseRefVersionValue(element) {
  const prefix = useSettingStore().editor.processEngine
  return getBusinessObject(element).get(`${prefix}:caseVersion`)
}
export function setCaseRefVersionValue(element, value) {
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    caseVersion: value
  })
}

export function getCaseRefTenantIdValue(element) {
  const prefix = useSettingStore().editor.processEngine
  return getBusinessObject(element).get(`${prefix}:caseTenantId`)
}
export function setCaseRefTenantIdValue(element, value) {
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    caseTenantId: value
  })
}

export function getBusinessKeyValue(element) {
  return hasBusinessKey(element)
}
export function setBusinessKeyValue(element, value) {
  if (value) {
    addBusinessKey(element)
  } else {
    removeBusinessKey(element)
  }
}

export function getBusinessKeyExpression(element) {
  return getBusinessKey(element)
}
export function setBusinessKeyExpression(element, value) {
  const modeling = useModelerStore().getModeling
  const camundaIn = findCamundaInWithBusinessKey(element)
  modeling.updateModdleProperties(element, camundaIn, {
    businessKey: value || ''
  })
}

export function getDelegateVariableMappingTypeValue(element) {
  return getDelegateVariableMappingType(element)
}
export function setDelegateVariableMappingTypeValue(element, value) {
  const prefix = useSettingStore().editor.processEngine
  const modeling = useModelerStore().getModeling
  const properties = {
    ...setDefaultVariableMappingProps()
  }
  if (value === 'class') {
    properties[`${prefix}:variableMappingClass`] = ''
  } else if (value === 'delegateExpression') {
    properties[`${prefix}:variableMappingDelegateExpression`] = ''
  }
  modeling.updateProperties(element, properties)
}

export function getVariableMappingDelegateExpressionValue(element) {
  const prefix = useSettingStore().editor.processEngine
  return getBusinessObject(element).get(`${prefix}:variableMappingDelegateExpression`)
}
export function setVariableMappingDelegateExpressionValue(element, value) {
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    variableMappingDelegateExpression: value || '',
    variableMappingClass: undefined
  })
}

export function getVariableMappingClassValue(element) {
  const prefix = useSettingStore().editor.processEngine
  return getBusinessObject(element).get(`${prefix}:variableMappingClass`)
}
export function setVariableMappingClassValue(element, value) {
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    variableMappingDelegateExpression: undefined,
    variableMappingClass: value || ''
  })
}

function addBusinessKey(element) {
  const modeling = useModelerStore().getModeling
  const businessObject = getBusinessObject(element)
  let extensionElements = businessObject.get('extensionElements')

  // (1) If there are no extension elements, create camunda:In and update element's properties
  if (!extensionElements) {
    extensionElements = createModdleElement('bpmn:ExtensionElements', {}, businessObject)
    const businessKeyItem = createBusinessKey(extensionElements)
    extensionElements.set('values', [businessKeyItem])
    modeling.updateProperties(element, {
      extensionElements
    })
  } else {
    // (2) Otherwise, add camunda:In to the existing values
    const businessKeyItem = createBusinessKey(extensionElements)
    addExtensionElements(element, businessObject, businessKeyItem)
  }
}
function createBusinessKey(parent) {
  const prefix = useSettingStore().editor.processEngine
  return createModdleElement(`${prefix}:In`, { businessKey: DEFAULT_BUSINESS_KEY }, parent)
}
function removeBusinessKey(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  const camundaInList = getExtensionElementsList(businessObject, `${prefix}:In`)
  const businessKeyItems = camundaInList.filter((camundaIn) => camundaIn.get('businessKey') !== undefined)
  removeExtensionElements(element, businessObject, businessKeyItems)
}

export function getCalledElementTypeOptions() {
  return [
    {
      value: 'bpmn',
      label: 'BPMN'
    },
    {
      value: 'cmmn',
      label: 'CMMN'
    }
  ]
}

export function getVariableMappingTypeOptions() {
  return [
    {
      value: 'class',
      label: '类名'
    },
    {
      value: 'delegateExpression',
      label: '代理表达式'
    }
  ]
}

function getDelegateVariableMappingType(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  if (businessObject.get(`${prefix}:variableMappingClass`) !== undefined) {
    return 'class'
  } else if (businessObject.get(`${prefix}:variableMappingDelegateExpression`) !== undefined) {
    return 'delegateExpression'
  }
  return ''
}

export const getBindingTypeOptions = (type) => {
  const options = [
    { value: 'latest', label: '最新版本' },
    { value: 'deployment', label: '部署版本' },
    { value: 'version', label: '指定版本' }
  ]
  if (type === 'bpmn') {
    options.push({ value: 'versionTag', label: '版本标签' })
  }
  return options
}

function setDefaultProps() {
  const prefix = useSettingStore().editor.processEngine
  return {
    calledElement: undefined,
    [`${prefix}:calledElementBinding`]: undefined,
    [`${prefix}:calledElementVersion`]: undefined,
    [`${prefix}:calledElementTenantId`]: undefined,
    [`${prefix}:variableMappingClass`]: undefined,
    [`${prefix}:variableMappingDelegateExpression`]: undefined,
    [`${prefix}:caseRef`]: undefined,
    [`${prefix}:caseBinding`]: undefined,
    [`${prefix}:caseVersion`]: undefined,
    [`${prefix}:caseTenantId`]: undefined
  }
}
const DEFAULT_BUSINESS_KEY = '#{execution.processBusinessKey}'
function setDefaultVariableMappingProps() {
  const prefix = useSettingStore().editor.processEngine
  return {
    [`${prefix}:variableMappingClass`]: undefined,
    [`${prefix}:variableMappingDelegateExpression`]: undefined
  }
}

// helper //////

function getCalledElementType(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  if (businessObject.get('calledElement') !== undefined) {
    return 'bpmn'
  } else if (businessObject.get(`${prefix}:caseRef`) !== undefined) {
    return 'cmmn'
  }
  return ''
}
export function hasBusinessKey(element) {
  return getBusinessKey(element) !== undefined
}
function getBusinessKey(element) {
  const camundaIn = findCamundaInWithBusinessKey(element)
  if (camundaIn) {
    return camundaIn.get('businessKey')
  }
}
function findCamundaInWithBusinessKey(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  const camundaInList = getExtensionElementsList(businessObject, `${prefix}:In`)
  for (const camundaIn of camundaInList) {
    const businessKey = camundaIn.get('businessKey')
    if (businessKey !== undefined) {
      return camundaIn
    }
  }
}
